【问题标题】:Using simple function as a Class with OOP features将简单函数用作具有 OOP 特性的类
【发布时间】:2019-06-14 07:32:06
【问题描述】:

看到非常有趣的代码here,我正在尝试通过以下代码将函数用作类:

def CF_ptrec(sname='', sage=0, sgender=''):
    name = sname
    age = sage
    gender=sgender

    def getname():          
          return name
    def setname(ssname):        
          global name; name = ssname
    def getgender():        
          return gender
    def setgender(ssgender):    
          global gender; gender = ssgender

    def getage():           
          return age
    def setage(ssage):          
        print("in setage fn; val rcd: ", ssage) # just for testing; 
        global age
        age = ssage

    def printrep():
        print("Name: ", name)
        print("Age: ", age)
        print("Gender: ", gender)
        print("===========================")

    return {        # a dictionary
    "getname":getname, "setname":setname, 
    "getage":getage, "setage":setage, 
    "getgender":getgender, "setgender":setgender, 
    "printrep": printrep }

我可以创建对象并调用函数来打印它们的详细信息:

# CREATE OBJECTS: 
arec = CF_ptrec("Ram", 5, "M")
brec = CF_ptrec("Tom", 15, "M")

# PRINT THEIR RECORDS: 
arec["printrep"]()
brec["printrep"]()

输出:

Name:  Ram
Age:  5
Gender:  M
===========================
Name:  Tom
Age:  15
Gender:  M
===========================

但是,如果我尝试更改这些对象的年龄值,则无法正常工作:

# CHANGE AGE VALUES: 
arec['setage'](25)
brec['setage'](25)

# PRINT RECORDS: 
arec["printrep"]()
brec["printrep"]()

输出:

in setage fn; val rcd:  25
in setage fn; val rcd:  25
Name:  Ram
Age:  5
Gender:  M
===========================
Name:  Tom
Age:  15
Gender:  M
===========================

问题出在哪里,如何解决?

【问题讨论】:

  • 当您将函数用作类时,实际上是在创建闭包。你可以在 Python 中查找一些关于非本地和闭包的主题。
  • 虽然作为一个练习很有趣,但查看充满 getter 和 setter 的 Python 闭包对我来说看起来很反模式。课程肯定会更好地为您服务(可能没有getter和setter)。在更简单的情况下,闭包也有其用途。
  • 我可以在没有getter和setter的情况下访问上面示例中对象的数据(姓名、年龄、性别)吗?

标签: python function class oop


【解决方案1】:

当您尝试设置这些值时,您指的是global 变量。您真正想要更改的变量不是全局,它们在CF_ptrec 的范围内。您需要改用nonlocal age。目前,您正在设置一个 全局 变量 age,但正在从 CF_ptrec 范围读取 age

【讨论】:

  • 所以nonlocal var 在内部函数中对外部函数的行为方式相同,就像global var 在函数中对全局命名空间的行为一样?
  • global 始终表示全局范围。 nonlocal 表示定义该变量的最近的非全局范围。
  • 好吧,碰巧最近的非全局范围引用了外部函数,是否存在最近的非全局范围可以引用其他内容的情况?
  • 当然。如果嵌套函数中有多层嵌套函数,nonlocal 可能会引用更高层的变量。
【解决方案2】:

在@Deceze 答案的基础上,这是您的示例,使用nonlocal 关键字修改:([编辑]:换句话说,这是您在应用@Deceze 答案时获得的代码)

def CF_ptrec(sname='', sage=0, sgender=''):
    name = sname
    age = sage
    gender=sgender

    def getname():          
        return name

    def setname(ssname):        
        nonlocal name
        name = ssname

    def getgender():        
        return gender

    def setgender(ssgender):    
        nonlocal gender
        gender = ssgender

    def getage():           
        return age

    def setage(ssage):          
        print("in setage fn; val rcd: ", ssage) # just for testing; 
        nonlocal age
        age = ssage

    def printrep():
        print("Name: ", name)
        print("Age: ", age)
        print("Gender: ", gender)
        print("===========================")

    return {        # a dictionary
    "getname":getname, "setname":setname, 
    "getage":getage, "setage":setage, 
    "getgender":getgender, "setgender":setgender, 
    "printrep": printrep }

您的代码中失败的值更改现在已被考虑在内并且运行良好:

# CHANGE AGE VALUES: 
arec['setage'](25)
brec['setage'](25)

# PRINT RECORDS: 
arec["printrep"]()
brec["printrep"]()

输出:

in setage fn; val rcd:  25
in setage fn; val rcd:  25
Name:  Ram
Age:  25
Gender:  M
===========================
Name:  Tom
Age:  25
Gender:  M
===========================

【讨论】:

  • 这与其他答案基本相同。这与您的高声誉不符。
  • 我并没有试图与众不同,正如它在介绍中明确指出的那样,这是您在应用@Deceze 答案时得到的代码!我相信对某些人来说查看扩展代码是有用的;它作为一个例子。
猜你喜欢
  • 2013-07-25
  • 2012-08-02
  • 1970-01-01
  • 1970-01-01
  • 2012-11-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多