【问题标题】:Applying the @staticmethod, python3应用@staticmethod,python3
【发布时间】:2014-01-04 05:14:12
【问题描述】:
class UserInput():
    users=[]
    def __init__(self, name,lista,listb,listc,listd):
        self.name=""
        self.lista=lista
        self.listb=listb
        self.listc=listc
        self.listd=listd


    @staticmethod
    def create_new_user(x):
        x=userinput("x","","","","")
        users.append(x)

我打算制作一个生成新用户的函数,只向用户返回一个名称,还没有列表,因此 x 在名称槽中。

我的问题:这是@staticmethod 的正确用法还是我错过了它的全部意义?

据我了解,在这种情况下,它允许用户使用 userinput.create_new_user('tim') 而无需预先定义类,tim=userinput("foo","","","","") ;它在现场创建它。

我试图将函数create_new_users 变成:

@staticmethod
def create_new_user():
    print("how many users do you want to create")
    x=int(input())
    y=0
    while y < x:
        print("assign the users names")
        name = input("")
        if name == "" or "None,none":
            raise SyntaxError("name cannot be None or empty")
            break

        name=userinput("","","","","")      
        userinput.users.append(name)
        y+=1

【问题讨论】:

  • 请更正你的缩进。
  • 这里也有语法错误
  • 对不起,我每次都忘记了
  • @qwwqwwq 现在我修复了缩进以及一些明显的语法,append(x) to nothing changed to users.append(x),它正在工作
  • tim=userinput("foo","","","",""); 不会创建一个类,而是它的一个实例。执行class ...: 主体后,就会创建该类。

标签: python static-methods


【解决方案1】:

在静态方法中你不能使用类变量,你的代码应该得到

NameError: global name 'users' is not defined

编辑:

使用userinput.users.append

【讨论】:

  • 对,但答案如何?
  • 是的,确实发生了,那么在这种情况下使用类方法会更好吗? @staticmethod 不得允许引用任何类变量。这意味着 id 必须已经创建了一个全局列表才能使我的函数工作;将@staticmethod 及其下的函数转换为@classmethod 会更有益吗?
  • 这是正确的用法,我只需要参考类中的列表即可。谢谢
  • @TimLayne 我肯定会在这里使用@classmethod
  • @glglgl 为什么你认为@classmethod 在这种情况下会更好地工作?如果我使用@classmethod,我必须先创建类,然后才能使用该函数,而在我的情况下,我可以立即使用该函数。
【解决方案2】:

使用@classmethod 将是最简单的替代方法。

class UserInput: # capitals! Look at PEP 8.
    users = [] # rearranged to the top for better readability

    def __init__(self, name, lista, listb, listc, listd):
        self.name = ""
        self.lista = lista
        self.listb = listb
        self.listc = listc
        self.listd = listd

    @classmethod
    def create_new_user(cls): # no need for x if you overwrite it immediately
        x = cls("x", "", "", "", "")
        cls.users.append(x) # easier access to this static attribute
        return x # for the caller having access to it as well.

如果我们将UserInput 子类化,它也可以工作,因为它使用新类。

但请注意,x = cls("x", "", "", "", "") 不会很有用;更好的做法

    @classmethod
    def create_new_user(cls, *a, **k): # no need for x if you overwrite it immediately
        x = cls(*a, **k) # pass the arguments given by the caller to __init__.
        cls.users.append(x) # easier access to this static attribute
        return x # for the caller having access to it as well.

我现在可以这样使用:

a = UserInput("foo", "whatever", "is", "needed", "here")

或者,如果我愿意,

a = UserInput.create_new_user("foo", "whatever", "is", "needed", "here")

另外将新用户附加到列表中。

如果您希望能够缩短参数列表,您也可以这样做:

    def __init__(self, name, lista=None, listb=None, listc=None, listd=None):
        self.name = name
        self.lista = lista if lista is not None else []
        self.listb = listb if listb is not None else []
        self.listc = listc if listc is not None else []
        self.listd = listd if listd is not None else []

如果它们真的是列表。如果它们是字符串,则可以使用另一个名称,并且由于字符串是不可变的,您可以简单地这样做

    def __init__(self, name, lista='', listb='', listc='', listd=''):
        self.name = name
        self.lista = lista
        self.listb = listb
        self.listc = listc
        self.listd = listd

并用

调用这些东西
a = UserInput.create_new_user("foo", listc=...) # all others are left empty
b = UserInput("bar") # all are left empty
c = UserInput.create_new_user("ham", lista=..., listd=...) # all others are left empty

既然你想出了一个不同的任务,我也会尝试处理它:

@classmethod
def create_new_users(cls): # several users!
    print("how many users do you want to create")
    num = int(input())
    for _ in range(num): # simpler iteration
        print("enter the user's name")
        name = input("") # in 3.x, this is always a string, so it cannot be None...
        # if name == "" or "None,none": # That won't work as you think.
        if name == '' or name.lower() == 'none': # but why disallow the string 'None'?
            # raise SyntaxError("name cannot be None or empty")
            raise RuntimeError("name cannot be None or empty") # or ValueError or alike
            # break not needed. raise jumps out without it as well.
        user = cls(name, "", "", "", "") # name is an input, not an output.
        cls.users.append(name)

但我想知道该类是否真的是存储新用户的正确位置,并且只适用于使用此功能创建的用户。或许将users列表直接喂入__init__,让这个函数更上一层楼会更好。


在这里使用@classmethod 的好处是您始终在正确的基础上工作。

假设你有一个UserInput 和上面的__init__() 方法。然后你可以继承它并做

UserInput.create_new_users()使用@classmethod 将是最简单的替代方法。

class UserInputStoring(UserInput):
    users = [] # this is only here, not at the parent.
    def __init__(self, *a, **k):
        super(UserInputStoring, self).__init__(*a, **k) # pass everything up as it was used
        self.users.append(self)

现在您可以在基类中拥有您的create_new_users() 并成为@classmethod,它会根据您的调用方式选择正确的__init__ 进行调用。

【讨论】:

  • 没有大写主要是因为懒惰,一旦我完成了就回去纠正大写之类的
  • 我添加该答案只是为了向您展示它最终的代码,因为当我尝试将其添加到评论中时,它不断删除结构并将其组织成段落形式
  • 我不理解我们的示例之间的区别,两者似乎都将一些信息返回到同一个列表中,你能解释一下我们的不同之处,除了一个是@classmethod,另一个是@staticmethod .两者都由userinput.create_new_users() 访问;您的使用所需的cls 参数。因此,在您的示例中,userinput 作为 cls 参数返回,其中我的不需要 cls。在这两个示例中,我都可以使用 userinput 父类来使用该函数,并且它似乎都返回相同的值。我们的区别是什么?除了事实上你的在某些方面被缩短了
  • 它隐含地使用cls 就是我的意思。除非可以在其他类中使用相同的 @staticmethod,否则除了隐式使用 cls 之外,我看不到我们示例中的主要区别
  • @TimLayne 没有太大区别,但 @classmethod 也适用于子类。一个例子:您可以将列表中的存储分隔到子类的__init__ 中。然后调用者可以选择是使用UserInput.create_new_users() 不存储列表还是使用UserInputStoring.create_new_users() 存储列表。
猜你喜欢
  • 2015-08-08
  • 1970-01-01
  • 2015-01-03
  • 2010-12-14
  • 1970-01-01
  • 2017-06-14
  • 2015-01-03
  • 1970-01-01
  • 2021-08-14
相关资源
最近更新 更多