鱼C论坛

 找回密码
 立即注册
查看: 3438|回复: 10

[技术交流] 写给新人,python的代码风格

[复制链接]
发表于 2018-2-4 23:28:41 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 蓝色王魂 于 2018-2-5 08:39 编辑

        今天在和群里的小伙伴聊天的时候有了写这篇文章的想法,其实我学python也就不到三个月的时间,但我敢说我python面向对象的基础我都掌握了,其实的剩下的无非是自学和积累经验,后面我打算用pygame写一个类似橙光的文字游戏编辑器,不过这不是我们今天要讨论的,今天我们要说的是python的代码风格。
        我先说点次要的,有以下几点, 函数定义 类定义 模块导入之间都要空行, =号 ==号等两边打空格,逗号后面打空格,注释和注释的内容同一缩进,能做到这些很简单——用pycharm,这些都做到,能有效提高你代码的可读性。
        这一段还是讲次要的,就是变量的名称,我自己的方法是,都用对应的英语单词,忘了就用拼音,然和类的名字用名词,方法用动词,变量定义用名词并且注意单复数,有了这些,其实你就不需要写注释了。
        接下来就是我要说的重点了,众所周知,python是2017的top1,我认为这主要是有三点原因:1.简洁优美的代码风格 2.方便维护 3.有很多的第三方库,代码风格主要是关于第一点和第二点的,python是一个面向对象的语言,所以面向对象的编程方式是python的精髓,这个小甲鱼老师都有提到,所以,我的观点就是,写任何程序都要用类与继承!!
       下面举一个例子,就是小甲鱼老师的那个经典的猜数字游戏,先来看一下按当时所学的我认为的一个比较好的实现。
import random

print('这是一个猜数字的小游戏')
secret = random.randint
count = 0
flag = 0

while 1:
    if count == 0:
        guess = int(input('请输入你要猜的数字(1-9):'))
    elif count < 3:
        guess = int(input('猜错啦,请重新输入:'))
    else:
        break
    if guess == secret:
        flag = 1
        break
    else:
        count += 1
if flag == 0:
    print('太菜了,猜三次都猜不出来')
else:
    print('你是小甲鱼肚子里的蛔虫吗')
再看一下类与对象的方法:
import random

class Game():

    def __init__(self):
        self.secret = random.randint(1, 9)
        self.count = 0
        self.flag = 0

    def guess(self):
        if self.count == 0:
            g = input('请输入你要猜的数字(1-9):')
        elif self.count < 3:
            g = input('猜错啦,请重新输入:')
        if self.count == 3:
            return 0
        return int(g)

    def judge(self):
        while 1:
            g = self.guess()
            if self.count == 3:
                break
            if g == self.secret:
                print('你是小甲鱼肚子里的蛔虫吗')
                self.flag = 13
            else:
                self.count += 1

    def run(self):
        self.judge()
        if self.flag == 1:
            print('游戏结束')
        else:
            print('太菜了,三次都猜不出来')


if __name__ == '__main__':
    game = Game()
    game.run()

        对游戏编程有些了解的鱼油肯定知道这种写法就是游戏的一般写法,两段代码完全是一回事,明显第一个很简洁,但是,由于python自己的优美语法,我敢说后面的代码给一个没学过python的人看都能看懂,这就是代码优美的威力,而且写成这样的形式很方便给这个游戏进行功能添加,你只要多加一个方法就行了,这就是我说的易于维护。
        我下面再发一个代码,是一个神经网络算法的实现,具体是用来识别数字的,因为原来的作者用的是python2,所以我自己进行了修改,把原来的注释都删除了,但我们主要是看的代码风格,如果对神经网络感兴趣,请移步http://neuralnetworksanddeeplearning.com/chap1.html
import random
import numpy as np

def sigmoid(a):
    return 1.0 / (1.0 + np.exp(-a))

def sigmoid_prime(z):
    return sigmoid(z)*(1-sigmoid(z))

class Network(object):

    def __init__(self, sizes):
        self.num_layers = len(sizes)
        self.sizes = sizes
        self.biases = [np.random.randn(y, 1) for y in sizes[1:]]
        self.weights = [np.random.randn(y, x)\
                        for x, y in zip(sizes[:-1], sizes[1:])]

    def feedforward(self, a):
        for b, w in zip(self.biases, self.weights):
            a = sigmoid(np.dot(w, a)+b)
        return a

    def SGD(self, training_data, epochs, mini_batch_size, eta\
            , test_data=None):
        if test_data:
            n_test = len(test_data)
        n = len(training_data)
        for j in range(epochs):
           random.shuffle(training_data)
           mini_batches = [training_data[k:k+mini_batch_size]\
                           for k in range(0, n, mini_batch_size)]
           for mini_batch in mini_batches:
               self.update_mini_batch(mini_batch, eta)
           if test_data:
               print('Epoch {0}: {1} / {2}'.format(\
                   j, self.evaluate(test_data), n_test))
           else:
               print('Epoch {0} complete'.format(j))

    def update_mini_batch(self, mini_batch, eta):
        nabla_b = [np.zeros(b.shape) for b in self.biases]
        nabla_w = [np.zeros(w.shape) for w in self.weights]
        for x, y in mini_batch:
            delta_nabla_b, delta_nabla_w = self.backprop(x, y)
            nabla_b = [nb+dnb for nb, dnb in zip(nabla_b, delta_nabla_b)]
            nabla_w = [nw+dnw for nw, dnw in zip(nabla_w, delta_nabla_w)]
        self.weights = [w-(eta/len(mini_batch))*nw for w, nw in zip(self.weights, nabla_w)]
        self.biases = [b - (eta/len(mini_batch)) * nb for b, nb in zip(self.biases, nabla_b)]

    def backprop(self, x, y):
        nabla_b = [np.zeros(b.shape) for b in self.biases]
        nabla_w = [np.zeros(w.shape) for w in self.weights]
        activation = x
        activations = [x]
        zs = []
        for b, w in zip(self.biases, self.weights):
            z = np.dot(w, activation) + b
            zs.append(z)
            activation = sigmoid(z)
            activations.append(activation)
        delta = self.cost_derivative(activations[-1], y) * \
            sigmoid_prime(zs[-1])
        nabla_b[-1] = delta
        nabla_w[-1] = np.dot(delta, activations[-2].T)
        for l in range(2, self.num_layers):
            z = zs[-l]
            sp = sigmoid_prime(z)
            delta = np.dot(self.weights[-l + 1].transpose(), delta) * sp
            nabla_b[-l] = delta
            nabla_w[-l] = np.dot(delta, activations[-l - 1].transpose())
        return (nabla_b, nabla_w)

    def evaluate(self, test_data):
        test_results = [(np.argmax(self.feedforward(x)), y) for (x, y) in test_data]
        return sum(int(x == y) for (x, y) in test_results)

    def cost_derivative(self, output_activations, y):
        return (output_activations-y)
        你们自己体会这个代码的优美吧。
        做一个小小的总结,对于新人来说,好的代码风格就和好的投篮姿势一样,如果你一开始就能掌握,那就能事半功倍,我花了一个多月才发现类的优点,然后一用就不可自拔,假设你已经不是新手了,而想成为python大神,首先你需要代码量到三万(基础),其次你需要对某一方面有深入了解,第三,最好对计算机科学有深入研究,这是我的观点。
        最后再扯几句,我发现写文章开头不用按好几个空格,一个tab搞定,这是我学python得到的经验,还有最后就是感谢小甲鱼老师,他的教程在b站python搜索第一位是有理由的,没有他,我根本不会对编程有兴趣,@小甲鱼, I love fishc.另外,我想有没有人给我介绍一下python在北京的实习,本人还是高中生,想多积累点经验,也是为以后学java做铺垫,万分感谢,qq569908467,如果有实习联系我,想要交流python的也行(男生必须学完零基础,女生不限)

评分

参与人数 1荣誉 +1 鱼币 +1 贡献 +1 收起 理由
小白要成神 + 1 + 1 + 1 感谢楼主无私奉献!

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-2-4 23:48:14 | 显示全部楼层
得了吧,你还是赶紧自己去搜一下google开源项目风格指南中的python代码规范以及PEP8的内容

这是业内已经成熟的规范,你不要自己去另起炉灶了

https://google.github.io/styleguide/pyguide.html
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-2-5 00:06:56 | 显示全部楼层
DarkmasterSugar 发表于 2018-2-4 23:48
得了吧,你还是赶紧自己去搜一下google开源项目风格指南中的python代码规范以及PEP8的内容

这是业内已经 ...

我这都是自己总结的,而且也观摩过大神的代码基本上是这种风格,但还是谢谢指正
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-2-5 00:21:15 | 显示全部楼层
@小甲鱼 求课后作业填坑
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-2-5 00:27:56 | 显示全部楼层
蓝色王魂 发表于 2018-2-5 00:06
我这都是自己总结的,而且也观摩过大神的代码基本上是这种风格,但还是谢谢指正

会总结当然是好事,不过我觉得你这样的帖容易误导部分新人
再者,大神的代码绝不会是和你贴出来的这样的,不规范的地方太多了,典型的高效学院风
比如单行长度有超过80字符的;
二元运算符两侧没有空格,且代码中前后不一致
采用\这样的很扎眼的换行方式
过长参数列表处理欠妥
类和函数都没有写文档等等

参考别人风格要有鉴别能力,有google这样的推荐规范就按推荐的来
你再看看random, numpy这样成熟的库的源代码是个什么风格,肯定不是长这样的
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-2-5 02:53:27 | 显示全部楼层
DarkmasterSugar 发表于 2018-2-5 00:27
会总结当然是好事,不过我觉得你这样的帖容易误导部分新人
再者,大神的代码绝不会是和你贴出来的这样的 ...

差不多就行了,我觉得不用要求每个人风格都一样,那个人是一个机器学习的工程师,这是他出的一个电子书的内容。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-2-5 02:54:30 | 显示全部楼层
本帖最后由 蓝色王魂 于 2018-2-5 03:21 编辑
DarkmasterSugar 发表于 2018-2-5 00:27
会总结当然是好事,不过我觉得你这样的帖容易误导部分新人
再者,大神的代码绝不会是和你贴出来的这样的 ...


还有,这代码是我改的,不是他的原版代码,所以会有细小问题是我自己疏忽了,那天用的idle编的不是pychram,我觉得有时候idle看起来舒服
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-2-5 02:58:33 | 显示全部楼层
蓝色王魂 发表于 2018-2-5 02:54
还有,这代码是我改的,不是他的原版代码,所以会有细小问题我懒得改,而且我说了,文档被我删了。

原版代码,python2的
"""
network.py
~~~~~~~~~~

A module to implement the stochastic gradient descent learning
algorithm for a feedforward neural network.  Gradients are calculated
using backpropagation.  Note that I have focused on making the code
simple, easily readable, and easily modifiable.  It is not optimized,
and omits many desirable features.
"""

#### Libraries
# Standard library
import random

# Third-party libraries
import numpy as np

class Network(object):

    def __init__(self, sizes):
        """The list ``sizes`` contains the number of neurons in the
        respective layers of the network.  For example, if the list
        was [2, 3, 1] then it would be a three-layer network, with the
        first layer containing 2 neurons, the second layer 3 neurons,
        and the third layer 1 neuron.  The biases and weights for the
        network are initialized randomly, using a Gaussian
        distribution with mean 0, and variance 1.  Note that the first
        layer is assumed to be an input layer, and by convention we
        won't set any biases for those neurons, since biases are only
        ever used in computing the outputs from later layers."""
        self.num_layers = len(sizes)
        self.sizes = sizes
        self.biases = [np.random.randn(y, 1) for y in sizes[1:]]
        self.weights = [np.random.randn(y, x)
                        for x, y in zip(sizes[:-1], sizes[1:])]

    def feedforward(self, a):
        """Return the output of the network if ``a`` is input."""
        for b, w in zip(self.biases, self.weights):
            a = sigmoid(np.dot(w, a)+b)
        return a

    def SGD(self, training_data, epochs, mini_batch_size, eta,
            test_data=None):
        """Train the neural network using mini-batch stochastic
        gradient descent.  The ``training_data`` is a list of tuples
        ``(x, y)`` representing the training inputs and the desired
        outputs.  The other non-optional parameters are
        self-explanatory.  If ``test_data`` is provided then the
        network will be evaluated against the test data after each
        epoch, and partial progress printed out.  This is useful for
        tracking progress, but slows things down substantially."""
        if test_data: n_test = len(test_data)
        n = len(training_data)
        for j in xrange(epochs):
            random.shuffle(training_data)
            mini_batches = [
                training_data[k:k+mini_batch_size]
                for k in xrange(0, n, mini_batch_size)]
            for mini_batch in mini_batches:
                self.update_mini_batch(mini_batch, eta)
            if test_data:
                print "Epoch {0}: {1} / {2}".format(
                    j, self.evaluate(test_data), n_test)
            else:
                print "Epoch {0} complete".format(j)

    def update_mini_batch(self, mini_batch, eta):
        """Update the network's weights and biases by applying
        gradient descent using backpropagation to a single mini batch.
        The ``mini_batch`` is a list of tuples ``(x, y)``, and ``eta``
        is the learning rate."""
        nabla_b = [np.zeros(b.shape) for b in self.biases]
        nabla_w = [np.zeros(w.shape) for w in self.weights]
        for x, y in mini_batch:
            delta_nabla_b, delta_nabla_w = self.backprop(x, y)
            nabla_b = [nb+dnb for nb, dnb in zip(nabla_b, delta_nabla_b)]
            nabla_w = [nw+dnw for nw, dnw in zip(nabla_w, delta_nabla_w)]
        self.weights = [w-(eta/len(mini_batch))*nw
                        for w, nw in zip(self.weights, nabla_w)]
        self.biases = [b-(eta/len(mini_batch))*nb
                       for b, nb in zip(self.biases, nabla_b)]

    def backprop(self, x, y):
        """Return a tuple ``(nabla_b, nabla_w)`` representing the
        gradient for the cost function C_x.  ``nabla_b`` and
        ``nabla_w`` are layer-by-layer lists of numpy arrays, similar
        to ``self.biases`` and ``self.weights``."""
        nabla_b = [np.zeros(b.shape) for b in self.biases]
        nabla_w = [np.zeros(w.shape) for w in self.weights]
        # feedforward
        activation = x
        activations = [x] # list to store all the activations, layer by layer
        zs = [] # list to store all the z vectors, layer by layer
        for b, w in zip(self.biases, self.weights):
            z = np.dot(w, activation)+b
            zs.append(z)
            activation = sigmoid(z)
            activations.append(activation)
        # backward pass
        delta = self.cost_derivative(activations[-1], y) * \
            sigmoid_prime(zs[-1])
        nabla_b[-1] = delta
        nabla_w[-1] = np.dot(delta, activations[-2].transpose())
        # Note that the variable l in the loop below is used a little
        # differently to the notation in Chapter 2 of the book.  Here,
        # l = 1 means the last layer of neurons, l = 2 is the
        # second-last layer, and so on.  It's a renumbering of the
        # scheme in the book, used here to take advantage of the fact
        # that Python can use negative indices in lists.
        for l in xrange(2, self.num_layers):
            z = zs[-l]
            sp = sigmoid_prime(z)
            delta = np.dot(self.weights[-l+1].transpose(), delta) * sp
            nabla_b[-l] = delta
            nabla_w[-l] = np.dot(delta, activations[-l-1].transpose())
        return (nabla_b, nabla_w)

    def evaluate(self, test_data):
        """Return the number of test inputs for which the neural
        network outputs the correct result. Note that the neural
        network's output is assumed to be the index of whichever
        neuron in the final layer has the highest activation."""
        test_results = [(np.argmax(self.feedforward(x)), y)
                        for (x, y) in test_data]
        return sum(int(x == y) for (x, y) in test_results)

    def cost_derivative(self, output_activations, y):
        """Return the vector of partial derivatives \partial C_x /
        \partial a for the output activations."""
        return (output_activations-y)

#### Miscellaneous functions
def sigmoid(z):
    """The sigmoid function."""
    return 1.0/(1.0+np.exp(-z))

def sigmoid_prime(z):
    """Derivative of the sigmoid function."""
    return sigmoid(z)*(1-sigmoid(z))
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-2-5 02:59:30 | 显示全部楼层
蓝色王魂 发表于 2018-2-5 02:58
原版代码,python2的

我想吐槽他的换行有加反斜杠有没加的。。。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-2-5 09:55:32 From FishC Mobile | 显示全部楼层
现在还在学学到30课就觉得后面越来越复杂了,不知道类是怎么一回事。感谢楼主分享
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-3-13 16:54:02 | 显示全部楼层
讲道理,我觉得这里不值得用类来实现。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-11-24 20:39

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表